#include "../inc/queue.h"

void CQ::init() {
	free_item_total = 1000;
    free_item_curr  = 1000;
    
	freeitems = (CQ_ITEM**)malloc(sizeof(CQ_ITEM*) * free_item_total);
    assert( freeitems );
	
	pthread_mutex_init(&cq_lock, NULL);
	this->head = NULL;
	this->tail = NULL;
}

void CQ::push(CQ_ITEM* item) {	
	item->next = NULL;
	
	pthread_mutex_lock(&this->cq_lock);
	
	if (this->tail == NULL) {
		this->head = item;
	} else {
		this->tail->next = item;
	}
	this->tail = item;
	
	pthread_mutex_unlock(&this->cq_lock);
}

CQ_ITEM* CQ::pop() {	
	CQ_ITEM* item = NULL;
	
	pthread_mutex_lock(&this->cq_lock);
	
	item = this->head;
	if (item != NULL) {
		this->head = item->next;
		if (this->head == NULL) {
			this->tail = NULL;
		}
	}
	
	pthread_mutex_unlock(&this->cq_lock);

	return item;
}

void CQ::free(CQ_ITEM* item) {
	pthread_mutex_lock(&this->cq_lock);
	
	if (item != NULL) {
		if (add_to_freelist(item) == -1) {	
			free(item);
		}
	}
	
	pthread_mutex_unlock(&this->cq_lock);
}

CQ_ITEM* CQ::item_from_freelist() {
    CQ_ITEM* item = NULL;
    
    if (free_item_curr > 0) {
        item = freeitems[-- free_item_curr];
    }
	
    return item;
}

int CQ::add_to_freelist(CQ_ITEM* item) {
    int ret = -1;
    
    if (free_item_curr < free_item_total) {
        freeitems[free_item_curr ++] = item;
        ret = 0;
    } else {
        int new_size = free_item_total * 2;
        CQ_ITEM** new_freeitems = (CQ_ITEM**)realloc(freeitems, new_size * sizeof(CQ_ITEM*));
        if (new_freeitems != NULL) {
            free_item_total = new_size;
            freeitems = new_freeitems;
            freeitems[free_item_curr ++] = item;
            ret = 0;
        }
    }
    
    return ret;
}